/**************************************************************
*  Apple LLVM version 10.0.0 (clang-1000.10.43.1)             *
*  Copyright (C) 2021 Xuan-Yu-San 307100890@qq.com.           *
*                                                             *
*  This file is part of little-nginx.                         *
*  Little-NGINX is a castration version NGINX for learning    *
*  HTTP Message.                                              *
*                                                             *
*  @file     Server.h                                         *
*  @github   https://gitee.com/xuanyusan/little_nginx.git     *
*  @license  MIT License (MIT)                                *
**************************************************************/

#ifndef RESPONSE_HPP
#define RESPONSE_HPP

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>

#include "util.hpp"
#include "Message.hpp"

using namespace std;

class Response: public Message {
private:
    string status;
    string status_message;
public:
    Response(string request_body);
    string json();
    string str();
    int get_status();
    void reset_response_str();
    void update_proxy_redirect();
    void update_header_params(string, int);
    void update_header_params(string, string);
    void update_header_params(string, pair<string, string>);
    ~Response();
    static Response render_template(string);
    static Response make_response(int, string="");
};

Response::Response(string request_body):Message(request_body) {
    istringstream strcin(request_body);
    string temp;
    strcin >> temp;
    this->protocol = temp;
    strcin >> temp;
    this->status = temp;
    strcin >> temp;
    this->status_message = temp;
    getline(strcin,temp);
    while(getline(strcin,temp)){
        temp.pop_back();
        if(temp.size() == 0) {
            break;
        }
        bool flag = false;
        for(int i=0;i<temp.size();i++){
            if(temp[i]==':') {
                this->header_params[temp.substr(0,i)] = temp.substr(i+2);
                flag = true;
                break;
            }
        }
        if (flag) {} else {
            break;
        }
    }
    while(getline(strcin,temp)){
        this->body_content += temp + "\n";
    }
}

void Response::reset_response_str() {
    string temp = "";
    temp += this->protocol + ' ' + this->status + ' ' + this->status_message + "\r\n";
    for (map<string, string>::iterator iter = this->header_params.begin(); iter != this->header_params.end(); iter++)
    {
        temp += iter->first + ": " + iter->second + "\r\n";
    }
    this->message_str = temp + "\r\n" + this->body_content;
}

string Response::json() {
    string temp = "";
    temp += "{\n";
    temp += "\t\"protocol\": \"" + this->protocol + "\"\n";
    temp += "\t\"status\": \"" + this->status + "\"\n";
    temp += "\t\"status_message\": \"" + this->status_message + "\"\n";
    for (map<string, string>::iterator iter = this->header_params.begin(); iter != this->header_params.end(); iter++)
    {
        temp += "\t\"" + iter->first + "\": \"" + iter->second + "\"\n";
    }
    temp += "}\n";
    return temp;
}

string Response::str() {
    return this->message_str;
}

int Response::get_status() {
    return atoi(this->status.c_str());
}

void Response::update_header_params(string key, int value){
    this->header_params[key] = to_string(value);
    this->reset_response_str();
}
void Response::update_header_params(string key, string value){
    value.erase(remove(value.begin(), value.end(), '\n'), value.end());
    this->header_params[key] = value;
    this->reset_response_str();
}
void Response::update_header_params(string key, pair<string, string> rep){
    string value = this->header_params[key];
    int index = value.find(rep.first);
    value.replace(index, rep.first.size(), rep.second);
    this->header_params[key] = value;
    this->reset_response_str();
}

Response::~Response() {}

Response Response::render_template(string path) {
    ifstream fp(path);
    if(!fp){
        return Response::make_response(404);
    }
    string html_content = "";
    string temp;
    while(getline(fp, temp)) {
        html_content += temp + "\n";
    }
    fp.close();
    Response response = Response("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 0\r\nDate: " + get_time("%W, %D %E %Y %h:%m:%s %Z") + "\r\nConnection: keep-alive\r\nServer: little_nginx/0.0.0\r\n\r\n"+html_content);
    response.update_header_params("Content-Length",html_content.size());
    return response;
}

Response Response::make_response(int status, string info) {
    if (status == 302) {
        string location = info;
        Response response302 = Response("HTTP/1.1 302 OK\r\nLocation: " + location + "\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 0\r\nDate: " + get_time() + "\r\nConnection: keep-alive\r\n\r\n");
        return response302;
    } else { // if (status == 404){
        Response response404 = Response("HTTP/1.1 404 Not Found\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 377\r\nDate: " + get_time("%W, %D %E %Y %h:%m:%s %Z") + "\r\nConnection: keep-alive\r\nServer: little_nginx/0.0.0\r\n\r\n<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n\t<meta charset=\"UTF-8\">\r\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n\t<title>Document</title>\r\n\t<style>\r\n\t\th1, p {\r\n\t\t\ttext-align: center;\r\n\t\t}\r\n\t</style>\r\n</head>\r\n<body>\r\n\t<h1>404 Not Found</h1>\r\n\t<hr>\r\n\t<p>little_nginx/0.0.0</p>\r\n</body>\r\n</html>");
        return response404;
    }
};

#endif